/////////////////////////////////////////////////////////////////////////////////////
// Include Files
#include "Interfaces\Process.h"
#include <process.h>

#include "Systems\Scene.h"

/////////////////////////////////////////////////////////////////////////////////////
// ABCProcess Implementation

void ABCProcess::StartProcess( uint_t _uiFrameRate )
{
	// find the frame rate, set running to false, start the thread
	m_uiFrameRate = _uiFrameRate;
	m_bRunning    = CE_FALSE;
	m_hThread     = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0);

	// wait for the thread to start running
	m_DataMutex.Lock();
	while( !m_bRunning )
	{
		m_DataMutex.Unlock();
		Sleep(10);
		m_DataMutex.Lock();
	}
	m_DataMutex.Unlock();
}
void ABCProcess::StopProcess()
{
	// set running to false, wait for the thread to quit
	m_DataMutex.Lock();
	m_bRunning = CE_FALSE;
	m_DataMutex.Unlock();

	WaitForSingleObject( m_hThread, INFINITE );
	CloseHandle(m_hThread);
	m_hThread = CE_NULL;
}

uint_t __stdcall ABCProcess::ThreadProc( void * _pParams )
{
	// cast the parameters to the correct type
	ABCProcess * pProcess = (ABCProcess *)_pParams;

	// get the time per frame
	pProcess->m_DataMutex.Lock();
	uint_t uiFrameRate = pProcess->m_uiFrameRate;
	pProcess->m_DataMutex.Unlock();

	float_t fFrameTime = uiFrameRate == 0 ? 0.0f : 1.0f / uiFrameRate;

	// call the begin function
	pProcess->ProcessBegin();

	// the frequency of the counter
	int64_t iFreq;
	QueryPerformanceFrequency( (LARGE_INTEGER*)&iFreq );

	// the count per frame
	int64_t iFrame = int64_t(iFreq * fFrameTime);

	// the count at which to perform the next update
	int64_t iTick;
	QueryPerformanceCounter( (LARGE_INTEGER*)&iTick );

	int64_t iPrev = iTick;

	// start the loop, protect the running variable
	pProcess->m_DataMutex.Lock();
	pProcess->m_bRunning = CE_TRUE;
	while( pProcess->m_bRunning )
	{
		// done checking the running variable
		pProcess->m_DataMutex.Unlock();

		// the current count
		int64_t iCurr;

		// tick
		QueryPerformanceCounter( (LARGE_INTEGER*)&iCurr );
		float_t fTime = (iCurr - iPrev) / (float_t)iFreq;
		pProcess->ProcessTick(fTime);

		// prepare for the next tick
		iPrev = iCurr;
		iTick += iFrame;

		// sleep for the remainder of the frame time
		if( iFrame != 0 )
		{
			QueryPerformanceCounter( (LARGE_INTEGER*)&iCurr );
			int_t iSleepTime = int_t(iTick - iCurr) / int_t(iFreq / 1000);
			if( iSleepTime >= 0 )
			{
				Sleep( (DWORD)iSleepTime );
			}
		}

		// protect the running variable
		pProcess->m_DataMutex.Lock();
	}
	// done checking the running variable
	pProcess->m_DataMutex.Unlock();



	//// use a stopwatch to keep the frame rate constant
	//stopwatch_t stopwatch;
	//stopwatch.Start();

	//// loop until running is set to false
	//pProcess->m_DataMutex.Lock();
	//while( pProcess->m_bRunning )
	//{
	//	// frame start
	//	pProcess->m_DataMutex.Unlock();

	//	// find the amount of time since the last frame
	//	float_t fElapsed = stopwatch.Elapsed();
	//	stopwatch.Reset();

	//	// process the frame
	//	pProcess->ProcessTick(fElapsed);

	//	// sleep for the remainder of the frame
	//	if( fFrameTime < 0.0f )
	//	{
	//		float_t fWaitTime = fFrameTime - stopwatch.Elapsed();
	//		if( fWaitTime > 0.0f ) Sleep( DWORD( fWaitTime * 1000 ) );
	//	}

	//	// frame end
	//	pProcess->m_DataMutex.Lock();
	//}
	//pProcess->m_DataMutex.Unlock();

	// call the end function
	pProcess->ProcessEnd();

	// complete
	return 0;
}
